/*
 * $Id: callbacks.c 7557b5d4d82b 2012/12/02 09:07:16 pgurumur $
 *
 * Copyright (c) 2006, 2007, 2008 Prabhu Gurumurthy <pgurumur@gmail.com>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * version "$Revision: 7557b5d4d82b $"
 * author "$Author: pgurumur $"
 */

#include "svn.h"

svn_error_t *
userpw_cb(svn_auth_cred_simple_t **cred, void *baton,
      const char *realm, const char *user, svn_boolean_t save, apr_pool_t *pool)
{
   struct _tclsvn *handle = (struct _tclsvn *)baton;
   save = save;

   svn_auth_cred_simple_t *ret = apr_pcalloc(pool, sizeof(*ret));
   if (ret) {
      realm = realm;
      const char *svnuser = (const char *)svn_auth_get_parameter(
            handle->ctx->auth_baton, SVN_AUTH_PARAM_DEFAULT_USERNAME);
      const char *svnpass = (const char *)svn_auth_get_parameter(
            handle->ctx->auth_baton, SVN_AUTH_PARAM_DEFAULT_PASSWORD);

      if (svnuser)
         ret->username = svn_string_ncreate(svnuser,
               strlen(svnuser), pool)->data;
      else if (user)
         ret->username = svn_string_ncreate(user, strlen(user), pool)->data;

      if (svnpass)
         ret->password = svn_string_ncreate(svnpass,
               strlen(svnpass), pool)->data;

      *cred = ret;
   }
   else
      error("%s: apr_pcalloc", __func__);

   return SVN_NO_ERROR;
}

svn_error_t *
user_cb(svn_auth_cred_username_t **cred, void *baton,
      const char *realm, svn_boolean_t save, apr_pool_t *pool)
{
   struct _tclsvn *handle = (struct _tclsvn *)baton;
   save = save;

   svn_auth_cred_username_t *ret = apr_pcalloc(pool, sizeof(*ret));
   if (ret) {
      realm = realm;
      const char *svnuser = (const char *)svn_auth_get_parameter(
            handle->ctx->auth_baton, SVN_AUTH_PARAM_DEFAULT_USERNAME);
      if (svnuser)
         ret->username = svn_string_ncreate(svnuser,
               strlen(svnuser), pool)->data;

      *cred = ret;
   }
   else
      error("%s: apr_pcalloc", __func__);

   return SVN_NO_ERROR;
}

svn_error_t *
recv_cb(void *baton, const char *path, const svn_dirent_t *dirent,
      const svn_lock_t *lock, const char *abs_path, apr_pool_t *pool)
{
   Tcl_Obj *handle = (Tcl_Obj *)baton;
   pool = pool;
   abs_path = abs_path;
   if (dirent != NULL) {
      Tcl_Obj *UrlPath = Tcl_NewStringObj(path, strlen(path));
      const char *temp = svn_time_to_cstring(dirent->time, pool);
      Tcl_Obj *ValuePtr = Tcl_NewListObj(0, NULL);
      Tcl_Obj *author = Tcl_NewStringObj(dirent->last_author, strlen(
               dirent->last_author));
      Tcl_Obj *size = Tcl_NewIntObj((int)(dirent->size));
      Tcl_Obj *revision = Tcl_NewIntObj((long)(dirent->created_rev));
      Tcl_Obj *date = Tcl_NewStringObj(temp, strlen(temp));
      Tcl_Obj *props = Tcl_NewIntObj((int)(dirent->has_props));

      Tcl_IncrRefCount(author);
      Tcl_ListObjAppendElement(svn_t->interp, ValuePtr, author);
      Tcl_DecrRefCount(author);

      Tcl_IncrRefCount(size);
      Tcl_ListObjAppendElement(svn_t->interp, ValuePtr, size);
      Tcl_DecrRefCount(size);

      Tcl_IncrRefCount(revision);
      Tcl_ListObjAppendElement(svn_t->interp, ValuePtr, revision);
      Tcl_DecrRefCount(revision);

      Tcl_IncrRefCount(date);
      Tcl_ListObjAppendElement(svn_t->interp, ValuePtr, date);
      Tcl_DecrRefCount(date);

      Tcl_IncrRefCount(props);
      Tcl_ListObjAppendElement(svn_t->interp, ValuePtr, props);
      Tcl_DecrRefCount(props);

      int retval = Tcl_DictObjPut(svn_t->interp, handle, UrlPath, ValuePtr);
      if (retval != 0)
         error("error inserting %s to tcl dict list", path);

      if (lock != NULL) {
         printf("file: %s\n", lock->path);
         printf("token: %s\n", lock->token);
         printf("locked author: %s\n", lock->owner);
         printf("comment for the lock: %s\n", lock->comment);
      }
   }

   return SVN_NO_ERROR;
}

void
notify_func(void *baton, const svn_wc_notify_t *notify, apr_pool_t *pool)
{
   baton = baton;
   pool = pool;

   if (notify) {
      if (notify->action == 9) {
         printf("A\t%s\n", notify->path);
      }
      else if (notify->action == 8) {
         printf("D\t%s\n", notify->path);
      }
      else if (notify->action == 10) {
         printf("U\t%s\n", notify->path);
      }
   }
}

svn_error_t *
status_cb(void *baton, const char *path, svn_wc_status2_t *status,
      apr_pool_t *pool)
{
   Tcl_Obj *handle = (Tcl_Obj *)baton;
   Tcl_Obj *repopath = Tcl_NewStringObj(path, strlen(path));
   Tcl_Obj *dict = Tcl_NewDictObj();
   int retval = 0;
   if (status) {
      Tcl_Obj *rev = Tcl_NewStringObj("revision", 8);
      Tcl_Obj *reval = Tcl_NewIntObj(status->entry->revision);
      retval = Tcl_DictObjPut(svn_t->interp, dict, rev, reval);

      Tcl_Obj *url = Tcl_NewStringObj("url", 3);
      Tcl_Obj *urlval = Tcl_NewStringObj(status->entry->url,
            strlen(status->entry->url));
      retval = Tcl_DictObjPut(svn_t->interp, dict, url, urlval);

      Tcl_Obj *uuid = Tcl_NewStringObj("uuid", 4);
      Tcl_Obj *uuidval = Tcl_NewStringObj(status->entry->uuid,
            strlen(status->entry->uuid));
      retval = Tcl_DictObjPut(svn_t->interp, dict, uuid, uuidval);

      if (status->entry->checksum) {
         Tcl_Obj *md5sum = Tcl_NewStringObj("checksum", 8);
         Tcl_Obj *checksum = Tcl_NewStringObj(status->entry->checksum,
               strlen(status->entry->checksum));
         retval = Tcl_DictObjPut(svn_t->interp, dict, md5sum, checksum);
      }

      Tcl_Obj *date = Tcl_NewStringObj("date", 4);
      const char *temp = svn_time_to_cstring(status->entry->text_time, pool);
      Tcl_Obj *dateval = Tcl_NewStringObj(temp, strlen(temp));
      retval = Tcl_DictObjPut(svn_t->interp, dict, date, dateval);

      retval = Tcl_DictObjPut(svn_t->interp, handle, repopath, dict);
   }

   return SVN_NO_ERROR;
}

svn_error_t *
info_cb(void *baton, const char *path, const svn_info_t *info,
      apr_pool_t *pool)
{
   Tcl_Obj *handle = (Tcl_Obj *)baton;
   Tcl_Obj *repopath = Tcl_NewStringObj(path, strlen(path));
   Tcl_Obj *dict = Tcl_NewDictObj();
   int retval = 0;
   if (info) {
      Tcl_Obj *url = Tcl_NewStringObj("url", 3);
      Tcl_Obj *urlval = Tcl_NewStringObj(info->URL, strlen(info->URL));
      retval = Tcl_DictObjPut(svn_t->interp, dict, url, urlval);

      Tcl_Obj *rev = Tcl_NewStringObj("revision", 8);
      Tcl_Obj *reval = Tcl_NewIntObj(info->rev);
      retval = Tcl_DictObjPut(svn_t->interp, dict, rev, reval);

      Tcl_Obj *rurl = Tcl_NewStringObj("rooturl", 7);
      Tcl_Obj *rurlval = Tcl_NewStringObj(info->repos_root_URL,
            strlen(info->repos_root_URL));
      retval = Tcl_DictObjPut(svn_t->interp, dict, rurl, rurlval);

      Tcl_Obj *uuid = Tcl_NewStringObj("uuid", 4);
      Tcl_Obj *uuidval = Tcl_NewStringObj(info->repos_UUID,
            strlen(info->repos_UUID));
      retval = Tcl_DictObjPut(svn_t->interp, dict, uuid, uuidval);

      Tcl_Obj *change = Tcl_NewStringObj("lastchange", 10);
      Tcl_Obj *changeval = Tcl_NewStringObj(info->last_changed_author,
            strlen(info->last_changed_author));
      retval = Tcl_DictObjPut(svn_t->interp, dict, change, changeval);

      Tcl_Obj *lastdate = Tcl_NewStringObj("lastdate", 8);
      const char *temp = svn_time_to_cstring(info->last_changed_date, pool);
      Tcl_Obj *dateval = Tcl_NewStringObj(temp, strlen(temp));
      retval = Tcl_DictObjPut(svn_t->interp, dict, lastdate, dateval);

      Tcl_Obj *lastrev = Tcl_NewStringObj("lastrev", 7);
      Tcl_Obj *lastreval = Tcl_NewIntObj(info->last_changed_rev);
      retval = Tcl_DictObjPut(svn_t->interp, dict, lastrev, lastreval);

      if ((info->kind != svn_node_none) || (info->kind != svn_node_unknown)) {
         Tcl_Obj *kind = Tcl_NewStringObj("kind", 4);
         Tcl_Obj *kindval = NULL;
         if (info->kind == svn_node_dir)
            kindval = Tcl_NewStringObj("directory", 9);
         else if (info->kind == svn_node_file)
            kindval = Tcl_NewStringObj("file", 4);

         if (kindval)
            retval = Tcl_DictObjPut(svn_t->interp, dict, kind, kindval);
      }

      Tcl_Obj *sched = Tcl_NewStringObj("schedule", 8);
      Tcl_Obj *schedval = NULL;
      if (info->schedule == svn_wc_schedule_normal)
         schedval = Tcl_NewStringObj("normal", 6);
      else if (info->schedule == svn_wc_schedule_add)
         schedval = Tcl_NewStringObj("add", 3);
      else if (info->schedule == svn_wc_schedule_delete)
         schedval = Tcl_NewStringObj("delete", 6);
      else if (info->schedule == svn_wc_schedule_replace)
         schedval = Tcl_NewStringObj("replace", 7);

      if (schedval)
         Tcl_DictObjPut(svn_t->interp, dict, sched, schedval);

      retval = Tcl_DictObjPut(svn_t->interp, handle, repopath, dict);
   }

   return SVN_NO_ERROR;
}

svn_error_t *
logmsg_cb(const char **log_msg, const char **tmp_file,
      const apr_array_header_t *commit_items, void *baton, apr_pool_t *pool)
{
   commit_items = commit_items;
   const char *mesg = (const char *)baton;
   if (mesg) {
      *log_msg = svn_string_ncreate(mesg, strlen(mesg), pool)->data;
      *tmp_file = NULL;
   }
   else
      error("%s internal error", __func__);

   return SVN_NO_ERROR;
}

svn_error_t *
sslserver_cb(svn_auth_cred_ssl_server_trust_t **cred, void *baton,
      const char *realm, apr_uint32_t failure,
      const svn_auth_ssl_server_cert_info_t *cert, svn_boolean_t save,
      apr_pool_t *pool)
{
   *cred = (svn_auth_cred_ssl_server_trust_t *)apr_pcalloc(pool,
         sizeof(**cred));
   if (*cred) {
      (*cred)->may_save = save;
      realm = realm;
      failure = failure;
      cert = cert;
      baton = baton;
   }

   return SVN_NO_ERROR;
}

svn_error_t *
plainpass_cb(svn_boolean_t *may_save, const char *realm, void *baton,
      apr_pool_t *pool)
{
   *may_save = FALSE;
   baton = baton;
   pool = pool;
   realm = realm;

   return SVN_NO_ERROR;
}

svn_error_t *
sslclient_cb(svn_auth_cred_ssl_client_cert_t **cred, void *baton,
      const char *realm, svn_boolean_t save, apr_pool_t *pool)
{
   *cred = NULL;
   baton = baton;
   realm = realm;
   save = save;
   pool = pool;

   return SVN_NO_ERROR;
}

svn_error_t *
sslpw_cb(svn_auth_cred_ssl_client_cert_pw_t **cred, void *baton,
      const char *realm, svn_boolean_t save, apr_pool_t *pool)
{
   struct _tclsvn *handle = (struct _tclsvn *)baton;
   svn_auth_cred_ssl_client_cert_pw_t *ret = (svn_auth_cred_ssl_client_cert_pw_t *)apr_pcalloc(pool, sizeof(*ret));

   if (ret) {
      const char *svnpass = (const char *)svn_auth_get_parameter(
            handle->ctx->auth_baton, SVN_AUTH_PARAM_DEFAULT_PASSWORD);
      if (svnpass) 
         ret->password = apr_pstrdup(pool, svnpass);

      ret->may_save = save;
      *cred = ret;
      realm = realm;
   }

   return SVN_NO_ERROR;
}

